package com.itheima.ai.repository;

import cn.hutool.core.util.IdUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Properties;

/**
 * 文件处理接口实现类
 *
 * @Author mr.wu
 * @Date 2025-11-6 16:49
 */
@Service
public class FileRepositoryImpl implements FileRepository{

    //文件存储存储到磁盘上的目标目录
    private static final String DIST_DIR = "d://files";

    private static final String PROPERTIES_NAME = "chat_pdf.properties";

    private static final String VECTORESTORE_NAME = "chat_vectore.json";

    private Properties properties = new Properties();


    /**
     * 保存PDF到磁盘和与会话ID的关系
     *
     * @param chatId
     * @param resource
     */
    @Override
    public void savePdfFile(String chatId, Resource resource) {
        try {
            //1. 生成唯一的PDF文件名

            //1.1 获取扩展名
            String extName = StringUtils.getFilenameExtension(resource.getFilename());

            //1.2 生成唯一前缀名
            String preName = IdUtil.fastSimpleUUID();

            //1.3 拼接完整文件名
            String fileName = preName + "." + extName;

            //2. 拷贝文件到指定的磁盘存储目录

            //2.1 目标目录如果不存在就自动创建
            if(Files.notExists(Paths.get(DIST_DIR))) {
                Files.createDirectory(Paths.get(DIST_DIR));
            }

            //2.2 拷贝文件
            FileCopyUtils.copy(resource.getInputStream(), Files.newOutputStream(Paths.get(DIST_DIR,fileName)));

            //3. 将会话ID与PDF文件名的关系存储起来
            properties.put(chatId,fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * IOC容器启动完成前，执行恢复资源操作：将properties文件从磁盘恢复到内存中和将vectoreStore文件从磁盘恢复到内存中
     */
    @PostConstruct
    public void loadResources(){
        //将properties文件从磁盘恢复到内存中
        Path propertiesPath = Paths.get(DIST_DIR, PROPERTIES_NAME);
        if(Files.exists(propertiesPath)) {
            try {
                properties.load(Files.newInputStream(propertiesPath ));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //将vectoreStore文件从磁盘恢复到内存中
        Path vectoreStorePath = Paths.get(DIST_DIR, VECTORESTORE_NAME);
        if(Files.exists(vectoreStorePath)) {
            SimpleVectorStore simpleVectorStore = (SimpleVectorStore)vectorStore;
            simpleVectorStore.load(vectoreStorePath.toFile());
        }
    }

    @Autowired
    private VectorStore vectorStore;

    /**
     * IOC容器关闭前，执行的持久化操作：将内存中的properties写到磁盘上 和 将内存中的向量数据库写到磁盘上
     */
    @PreDestroy
    public void persistence() {
        Path propertiesPath = Paths.get(DIST_DIR, PROPERTIES_NAME);
        try {
            if(Files.exists(Paths.get(DIST_DIR) )) {
                //将内存中的properties写到磁盘上
                properties.store(Files.newOutputStream(propertiesPath), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

                //将内存中的向量数据库写到磁盘上
                SimpleVectorStore simpleVectorStore = (SimpleVectorStore)vectorStore;
                simpleVectorStore.save(Paths.get(DIST_DIR, VECTORESTORE_NAME).toFile());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取PDF文件
     *
     * @param chatId
     * @return
     */
    @Override
    public Resource getPdfFile(String chatId) {
        String fileName = properties.getProperty(chatId);
        Resource resource = new FileSystemResource(Paths.get(DIST_DIR, fileName).toFile());
        return resource;
    }
}
